package crypto;
import java.io.UnsupportedEncodingException;
import java.security.*;

import utils.ByteTree;

/**
 * this class is a wrapping class for java.security.messeageDigest class
 * which provides cryptographic services such as common hash functions used
 * in the scope of this project.
 */
public class HashFunction {
	// private member of HashFunction class
	private MessageDigest messegeDigest;
	private int bitsOutLen;

	/**
	 * constructor for the HashFunction class.
	 * receives a byte array representing a string and produces an instance 
	 * message digest with the relevant hash function.
	 * if string is not a supported algorithm, raise an exception.
	 * 
	 * @param algorithm - byte[] with a string that represents a hash function
	 * @throws UnsupportedEncodingException - if local  machine doesnt support ascii
	 */
	public HashFunction(byte[] algorithm) throws UnsupportedEncodingException {

		this(new String(algorithm, "US-ASCII"));
	}

	/**
	 * Receives a string str and returns an instance of hash function which
	 * implements the algorithm descirbed by the string. 
	 * @param str
	 * @throws UnsupportedEncodingException - if local machine doesnt support ascii
	 */
	public HashFunction(String str) throws UnsupportedEncodingException {
		// should i make sure it's only sha family or does the caller do that?
		try {
			this.messegeDigest = MessageDigest.getInstance(str);
			this.bitsOutLen = messegeDigest.getDigestLength() * 8;
		} 
		catch (NoSuchAlgorithmException e) {
			System.out.println("Error: algorithem " + str + "is not supported");
			e.printStackTrace();
		}
	}

	/**
	 * Returns the string representation of the algorithm implemented in hash function instance.
	 * @return string (e.g. "SHA-256"
	 */
	public String getAlgorithm(){
		return this.messegeDigest.getAlgorithm();
	}

	/**
	 * returns output length in bits of the algorithm implemented in hash function instance.
	 * @return length in bits, or 0 if algorithm provider does not support it.
	 */

	public int getBitsOutLen(){
		return this.bitsOutLen;
	}

	/** 
	 * Receives a byte array byteArr and invokes the digest 
	 * of the hash function instance.
	 * @param byte[]
	 * @return byte[], containing getDigestLength bytes. 
	 */
	public byte[] digest(byte[] byteArr) {
		this.messegeDigest.reset();
		return this.messegeDigest.digest(byteArr); 
	}

	/**
	 * Receives a ByteTree bt and returns the hash function whose name is represented by bt.
	 * @param bt
	 * @return HashFunction hash
	 * @throws UnsupportedEncodingException - if string is not encoded using ascii
	 */
	public HashFunction(ByteTree bt) throws UnsupportedEncodingException{
		this(bt.getData());
	}

}
